dbtにおけるモデル(models)の記法に関するベストプラクティス #dbt
アライアンス事業部 エンジニアグループ モダンデータスタック(MDS)チームのしんやです。
dbtはクラウド型データウェアハウス(DWH)におけるデータ変換に特化したツールです。非常に使い勝手が良く便利なツールである一方、様々な機能が提供されているのでいざ使ってみよう!となると『何をどうやって作り上げていけば良いんだろう?』『この場合のルールや制限はどういうものがあるの?どういう取り決めをもって扱えば良いんだろう?』という風に思うこともあるかと思います。(実際私自身そう感じました)
そんなユーザーの疑問や悩みを解決する、いわゆるdbtユーザー向けのガードレール的な存在となりうるコンテンツがdbt社から展開されています。それが『dbtベストプラクティスガイド(Best practice guides)』です。構造、スタイル、セットアップなど、dbt Labsの現在の視点を通した「ベストプラクティス」がまとめられています。
そこで当エントリでは、幾つか展開されている「dbtベストプラクティスガイド」で紹介されているコンテンツの中から『dbtにおけるモデル(models)の書き方』に関するものを紹介し、読み解いていきたいと思います。
目次
dbtモデル(dbt models)の記法に関するベストプラクティス
モデルの名称
- ✅ モデルの名前は複数名とすべきです。
- 例)
customers
,orders
,products
- 例)
- dbtモデルの名称にはアンダースコアを使用し、ドットは避けましょう。
- ✅
models_without_dots
- ❌
models.with.dots
- ほとんどのデータ・プラットフォームでは、
database.schema.object
を区切るのにドットを使うので、ドットの代わりにアンダースコアを使うと、引用符で囲む必要が減り、dbt Cloudの特定の部分で問題が発生するリスクも減ります。
- ✅
モデル内の各種要素・項目の書き方
- ✅ 各モデルは主キー(Primary Key)を持つべきです。
- ✅ モデルにおける主キーの名称は
account_id
のように、<object>_id
という名前にしましょう。これにより、下流の結合されたモデルでどのidが参照されているのかを簡単に知ることができます。 - ✅ キーは文字列データ型でなければなりません。
- ✅ スタイルガイドを定める上では「一貫性」が何より重要です。可能であれば、モデル間で同じフィールド名を使いましょう。たとえば、customersテーブルのキーは
user_id
や'id'
ではなく、customer_id
という名前にすべきです。 - ❌ 略語や別名は使用せず、簡潔さよりも読みやすさを重視してください。
customer
にcust
、orders
にo
というような略称を使ってしまうと混乱を招きかねません。 - ❌ dbtで対応しているデータウェアハウスで使われている予約語をカラム名として使用しないようにしてください。
- ✅ ブール値(boolean)には
is_
またはhas_
を先頭に付けてください。 - ✅ タイムスタンプに関する列名は
<event>_at
(例えばcreated_at
)と命名すべき、且つUTCであるべきです。- 異なるタイムゾーンを使用する場合は、接尾辞(
created_at_pt
)で示すようにしましょう。 - 参考:タイムゾーン表示と時差一覧
- 異なるタイムゾーンを使用する場合は、接尾辞(
- ✅ 日付に関する列名は
<event>_date
とすべきです。- 例)
created_date
- 例)
- イベントに関する列名は「過去形」表記にすべきです。
- 例)
created
(作成された)updated
(更新された)deleted
(削除された)
- 例)
- ✅ 価格/売上に関する列名は10進数で指定すべきです。
- 19.99ドルの場合は
19.99
:多くのアプリデータベースは価格をセント単位の整数として保存します。 - 10進数以外の通貨を使用する場合は、接尾辞を付けましょう。 例)
price_in_cents
- 19.99ドルの場合は
- ✅ スキーマ名、テーブル名、カラム名は
snake_case
でなければなりません。- スネークケース(snake_case)とは、単語のつなぎ目を「_(アンダースコア)」で接続し、各単語の最初の文字を小文字で書く書式。
- スネークケース - Wikipedia
- ✅ データソースに関する用語ではなく、ビジネス用語に基づいた名前を使用するようにしてください。
- 例) ソース・データベースが
user_id
を使用しているが、ビジネスではcustomer_id
と呼んでいる場合、モデルではcustomer_id
を使用します。
- 例) ソース・データベースが
- ✅ モデルのバージョンは、一貫性を保つために接尾辞
_v1
、_v2
などを使用しましょう。- 例)
customers_v1
、customers_v2
- 例)
- ✅ データ型の順序を統一し、下の例のように、型ごとに列をグループ化し、ラベルを付けることを検討してください。このような形にすることで、結合エラーを最小化し、モデルを読みやすくします。
- また、データの下流の消費者がデータ型を理解し、必要な列のためにモデルをスキャンするのを助けます。
id
、string
、numerics
、boolean
、dates
、timestamps
の順で使用するのが望ましいです。
- また、データの下流の消費者がデータ型を理解し、必要な列のためにモデルをスキャンするのを助けます。
共通テーブル式(CTE/Common Table Expression)を使用
dbtにおけるSQLモデルの記述は、共通テーブル式(CTE/Common Table Expression)で書くことを推奨しています。この書き方を踏襲することで複雑な処理が(他者にとっても)読みやすくなる、処理のボトルネックやエラー等発生した際の特定もしやすくなる、といったポイントがその理由となっています。この辺りは普段からCTEを使っていないと慣れない部分かなと思いますが、言われてみれば確かに!という感じでもありますので、ここはこのルールに従い、いい感じでCTEを活用していくようにしていきたいですね。
「なぜdbt SQL modelsでCTEを使うのか」については 『イチから始めるデータ活用!dbt編』で発表したスライド資料でも言及しています。
SQLモデルではSELECT文で処理を記述
前述『共通テーブル式(CTE)』を使うということは、必然的に(SQL)モデル内ではSELECT文(Select statetment)を使う形となります。これについてもdbt社ではその理由・ポイントを幾つか紹介しています。
「なぜdbt SQL modelsでSELECT文を使うのか」については 『イチから始めるデータ活用!dbt編』で発表したスライド資料でも言及しています。
(SQL)モデルの記法サンプル
上記のルールを踏まえた形での「記法サンプル」は以下のようなものになります。
with source as ( select * from {{ source('ecom', 'raw_orders') }} ), renamed as ( select ---------- ids id as order_id, store_id as location_id, customer as customer_id, ---------- strings status as order_status, ---------- numerics (order_total / 100.0)::float as order_total, (tax_paid / 100.0)::float as tax_paid, ---------- booleans is_fulfilled, ---------- dates date(order_date) as ordered_date, ---------- timestamps ordered_at from source ) select * from renamed
まとめ
という訳で、dbtにおけるベストプラクティスの1つ『dbtモデルの記法に関するベストプラクティス』の紹介でした。
dbtにおける中核処理である『モデル』については一番触れる機会が多い、記述量が多くなる要素となります。dbtならではの癖のようなもの(例えばCTEとか)もについては慣れが必要ではありますが、理由を紐解いてみると納得出来る部分もありますのでこれはこれで『ルールに従う事の効果』を期待しつつ身に付けて行きたいところではありますね。